/***************************************************************************
*  Lowlayer.cpp
*
*  July 2007
*  Copyright  2007  RuijinZheng,China
*  Email mebetop@126.com
****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#include "Lowlayer.hpp"
////////////////
/// ------>  public funtions
Lowlayer::Lowlayer(const old_connect *origconnect,const old_recv *origrecv,const old_send *origsend,
const old_recvfrom *origrecvfrom,const old_sendto *origsendto) throw (const string &)
{
      if((origconnect!=NULL)&&(origrecv!=NULL)&&(origsend!=NULL)&&(origrecvfrom!=NULL)
          &&(origsendto!=NULL)){
         oldconnect=origconnect;
         oldrecv=origrecv;
         oldsend=origsend;
         oldsendto=origsendto;
         oldrecvfrom=origrecvfrom;
       }
      else {
           throw string("pass null orignal function ( for  example: connect(),read(),etc. ) \
                 pointers to layer constructor");
       }
      char *ptimeout = getenv("CONNECTTIMEOUT");
      if(ptimeout==NULL){
           utimeout=20;
       }
      else{
           utimeout=atoi(ptimeout);
       }
}

Lowlayer::~Lowlayer()
{
    
}
/// Http Status Code and Reason Phrase

/// The Status-Code element is a 3-digit integer result code of the
/// attempt to understand and satisfy the request. These codes are fully
/// defined in section 10. The Reason-Phrase is intended to give a short
/// textual description of the Status-Code. The Status-Code is intended
/// for use by automata and the Reason-Phrase is intended for the human
/// user. The client is not required to examine or display the Reason-
/// Phrase.

/// The first digit of the Status-Code defines the class of response. The
/// last two digits do not have any categorization role. There are 5
/// values for the first digit:

/// - 1xx: Informational - Request received, continuing process

/// - 2xx: Success - The action was successfully received,
/// understood, and accepted

/// - 3xx: Redirection - Further action must be taken in order to
/// complete the request

/// - 4xx: Client Error - The request contains bad syntax or cannot
/// be fulfilled

/// - 5xx: Server Error - The server failed to fulfill an apparently
/// valid request

/// The individual values of the numeric status codes defined for
/// HTTP/1.1, and an example set of corresponding Reason-Phrase's, are
/// presented below. The reason phrases listed here are only
/// recommendations -- they MAY be replaced by local equivalents without
/// affecting the protocol.

/// Status-Code =
/// "100" ; Section 10.1.1: Continue
/// | "101" ; Section 10.1.2: Switching Protocols
/// | "200" ; Section 10.2.1: OK
/// | "201" ; Section 10.2.2: Created
/// | "202" ; Section 10.2.3: Accepted
/// | "203" ; Section 10.2.4: Non-Authoritative Information
/// | "204" ; Section 10.2.5: No Content
/// | "205" ; Section 10.2.6: Reset Content
/// | "206" ; Section 10.2.7: Partial Content
/// | "300" ; Section 10.3.1: Multiple Choices
/// | "301" ; Section 10.3.2: Moved Permanently
/// | "302" ; Section 10.3.3: Found
/// | "303" ; Section 10.3.4: See Other
/// | "304" ; Section 10.3.5: Not Modified
/// | "305" ; Section 10.3.6: Use Proxy
/// | "307" ; Section 10.3.8: Temporary Redirect
/// | "400" ; Section 10.4.1: Bad Request
/// | "401" ; Section 10.4.2: Unauthorized
/// | "402" ; Section 10.4.3: Payment Required
/// | "403" ; Section 10.4.4: Forbidden
/// | "404" ; Section 10.4.5: Not Found
/// | "405" ; Section 10.4.6: Method Not Allowed
/// | "406" ; Section 10.4.7: Not Acceptable

/// | "407" ; Section 10.4.8: Proxy Authentication Required
/// | "408" ; Section 10.4.9: Request Time-out
/// | "409" ; Section 10.4.10: Conflict
/// | "410" ; Section 10.4.11: Gone
/// | "411" ; Section 10.4.12: Length Required
/// | "412" ; Section 10.4.13: Precondition Failed
/// | "413" ; Section 10.4.14: Request Entity Too Large
/// | "414" ; Section 10.4.15: Request-URI Too Large
/// | "415" ; Section 10.4.16: Unsupported Media Type
/// | "416" ; Section 10.4.17: Requested range not satisfiable
/// | "417" ; Section 10.4.18: Expectation Failed
/// | "500" ; Section 10.5.1: Internal Server Error
/// | "501" ; Section 10.5.2: Not Implemented
/// | "502" ; Section 10.5.3: Bad Gateway
/// | "503" ; Section 10.5.4: Service Unavailable
/// | "504" ; Section 10.5.5: Gateway Time-out
/// | "505" ; Section 10.5.6: HTTP Version not supported
/// | extension-code

/// Http Status Code and Reason Phrase

bool Lowlayer::Acthttpproxy(const int &sock,const sockaddr_in &in,const string &username,
              const string &password){

      char buf[8192];
      if((username.length()==0)&&(password.length()==0)){
            memset(buf,0,8192);
            sprintf(buf,"%s%s%s%d%s%s%s%s%d%s","CONNECT ",inet_ntoa(in.sin_addr),
                   ":",ntohs(in.sin_port)," HTTP/1.1\r\n","HOST: ",
                   inet_ntoa(in.sin_addr),":",ntohs(in.sin_port),"\r\n\r\n");
       }
      else{
            char chrBase64[4096];
            memset(chrBase64,0,4096);
            memset(buf,0,8192);
            sprintf(buf,"%s:%s",username.c_str(),password.c_str());
            Base64Enc(chrBase64,buf,strlen(buf));
            memset(buf,0,8192);
            string stringbase64=chrBase64;
            sprintf(buf,"%s%s%s%d%s%s%s%s%d%s%s%s%s%s%s%s",
                 "CONNECT ",inet_ntoa(in.sin_addr),
                   ":",ntohs(in.sin_port)," HTTP/1.1\r\n","HOST: ",
                   inet_ntoa(in.sin_addr), ":",ntohs(in.sin_port),
                   " \r\n","Authorization: Basic ",
                   stringbase64.c_str(), " \r\n\r\n",
                   "Proxy-Authorization: Basic ",stringbase64.c_str(),
                   " \r\n\r\n");
        }
       if(!Sendtoserver(sock,buf,strlen(buf))){
     	     return false;
        }
       memset(buf,0,8192);
       if(Recvfromserver(sock,buf,8192)==-1){
    	     return false;
        }
      char responsehead[14];
      strncpy(responsehead,buf,5);
      responsehead[4]='\0';
      if((strcmp(responsehead,"http")||strcmp(responsehead,"HTTP"))&&(strstr(buf,"200"))){
    	   // cout<<"ready to use http1.1(CONNECT) proxy server....... "<<endl;
           return true;
       }
      else{
           strncpy(responsehead,buf,13);
           responsehead[13]='\0';
           Errordeliver("when acting http proxy communication ,http proxy server returned failure information",responsehead); 
           return false;
       }
           
}
/*
SOCKS: A protocol for TCP proxy across firewalls

            Ying-Da Lee
        Principal Member Technical Staff
          NEC Systems Laboratory, CSTC
            ylee@syl.dl.nec.com

SOCKS was originally developed by David Koblas and subsequently modified
and extended by me to its current running version -- version 4. It is a
protocol that relays TCP sessions at a firewall host to allow application
users transparent access across the firewall. Because the protocol is
independent of application protocols, it can be (and has been) used for
many different services, such as telnet, ftp, finger, whois, gopher, WWW,
etc. Access control can be applied at the beginning of each TCP session;
thereafter the server simply relays the data between the client and the
application server, incurring minimum processing overhead. Since SOCKS
never has to know anything about the application protocol, it should also
be easy for it to accommodate applications which use encryption to protect
their traffic from nosey snoopers.

Two operations are defined: CONNECT and BIND.

1) CONNECT

The client connects to the SOCKS server and sends a CONNECT request when
it wants to establish a connection to an application server. The client
includes in the request packet the IP address and the port number of the
destination host, and userid, in the following format.

        +----+----+----+----+----+----+----+----+----+----+....+----+
        ¦ VN ¦ CD ¦ DSTPORT ¦      DSTIP        ¦ USERID      ¦NULL¦
        +----+----+----+----+----+----+----+----+----+----+....+----+
# of bytes:      1    1      2              4          variable      1

VN is the SOCKS protocol version number and should be 4. CD is the
SOCKS command code and should be 1 for CONNECT request. NULL is a byte
of all zero bits.

The SOCKS server checks to see whether such a request should be granted
based on any combination of source IP address, destination IP address,
destination port number, the userid, and information it may obtain by
consulting IDENT, cf. RFC 1413.  If the request is granted, the SOCKS
server makes a connection to the specified port of the destination host.
A reply packet is sent to the client when this connection is established,
or when the request is rejected or the operation fails.

        +----+----+----+----+----+----+----+----+
        ¦ VN ¦ CD ¦ DSTPORT ¦      DSTIP        ¦
        +----+----+----+----+----+----+----+----+
# of bytes:      1    1      2              4

VN is the version of the reply code and should be 0. CD is the result
code with one of the following values:

    90: request granted
    91: request rejected or failed
    92: request rejected becasue SOCKS server cannot connect to
        identd on the client
    93: request rejected because the client program and identd
        report different user-ids

The remaining fields are ignored.

The SOCKS server closes its connection immediately after notifying
the client of a failed or rejected request. For a successful request,
the SOCKS server gets ready to relay traffic on both directions. This
enables the client to do I/O on its connection as if it were directly
connected to the application server.


2) BIND

The client connects to the SOCKS server and sends a BIND request when
it wants to prepare for an inbound connection from an application server.
This should only happen after a primary connection to the application
server has been established with a CONNECT.  Typically, this is part of
the sequence of actions:

-bind(): obtain a socket
-getsockname(): get the IP address and port number of the socket
-listen(): ready to accept call from the application server
-use the primary connection to inform the application server of
the IP address and the port number that it should connect to.
-accept(): accept a connection from the application server

The purpose of SOCKS BIND operation is to support such a sequence
but using a socket on the SOCKS server rather than on the client.

The client includes in the request packet the IP address of the
application server, the destination port used in the primary connection,
and the userid.

        +----+----+----+----+----+----+----+----+----+----+....+----+
        ¦ VN ¦ CD ¦ DSTPORT ¦      DSTIP        ¦ USERID      ¦NULL¦
        +----+----+----+----+----+----+----+----+----+----+....+----+
# of bytes:      1    1      2              4          variable      1

VN is again 4 for the SOCKS protocol version number. CD must be 2 to
indicate BIND request.

The SOCKS server uses the client information to decide whether the
request is to be granted. The reply it sends back to the client has
the same format as the reply for CONNECT request, i.e.,

        +----+----+----+----+----+----+----+----+
        ¦ VN ¦ CD ¦ DSTPORT ¦      DSTIP        ¦
        +----+----+----+----+----+----+----+----+
# of bytes:      1    1      2              4

VN is the version of the reply code and should be 0. CD is the result
code with one of the following values:

    90: request granted
    91: request rejected or failed
    92: request rejected becasue SOCKS server cannot connect to
        identd on the client
    93: request rejected because the client program and identd
        report different user-ids.

However, for a granted request (CD is 90), the DSTPORT and DSTIP fields
are meaningful.  In that case, the SOCKS server obtains a socket to wait
for an incoming connection and sends the port number and the IP address
of that socket to the client in DSTPORT and DSTIP, respectively. If the
DSTIP in the reply is 0 (the value of constant INADDR_ANY), then the
client should replace it by the IP address of the SOCKS server to which
the cleint is connected. (This happens if the SOCKS server is not a
multi-homed host.)  In the typical scenario, these two numbers are
made available to the application client prgram via the result of the
subsequent getsockname() call.  The application protocol must provide a
way for these two pieces of information to be sent from the client to
the application server so that it can initiate the connection, which
connects it to the SOCKS server rather than directly to the application
client as it normally would.

The SOCKS server sends a second reply packet to the client when the
anticipated connection from the application server is established.
The SOCKS server checks the IP address of the originating host against
the value of DSTIP specified in the client's BIND request.  If a mismatch
is found, the CD field in the second reply is set to 91 and the SOCKS
server closes both connections.  If the two match, CD in the second
reply is set to 90 and the SOCKS server gets ready to relay the traffic
on its two connections. From then on the client does I/O on its connection
to the SOCKS server as if it were directly connected to the application
server.



For both CONNECT and BIND operations, the server sets a time limit
(2 minutes in current CSTC implementation) for the establishment of its
connection with the application server. If the connection is still not
establiched when the time limit expires, the server closes its connection
to the client and gives up.
*/
bool Lowlayer::Actsocks4proxy(const int &sock,const sockaddr_in &in){
	   //cout<<"preparing to communicate with proxy server "<<endl;
      unsigned char buf[BUFFERSIZE];
      int ret;
     // int sendlen = Makesocks4request(buf,in);
      short sport = in.sin_port;
      char * paddr = ( char *)&in.sin_addr.s_addr;
      memset(buf,0,BUFFERSIZE);
      buf[0] = 0x04;
      buf[1] = 0x01;
      memcpy(buf + 2,&sport,2);
      memcpy(buf + 4,paddr,4);
      memcpy(buf + 8,"a",strlen("a"));
      /// you can change "1" as any other you like
      buf[ 8 + strlen("a") ] = 0;
      
      if(!Sendtoserver(sock,(const char*)buf,8+strlen("a")+1)){
    	     return false;
       }
     
      memset(buf,0,BUFFERSIZE);
     
      ret = Recvfromserver(sock,(char*)buf,BUFFERSIZE);
      
       if(ret==-1){
    	   Errordeliver("bad size of data received",strerror(errno));
    	   return false;
       }
      if(ret != 8 ){
    	   Errordeliver("when receiving information from socks4 proxy server","bad size of data received");
    	   return false;
      }
      if( buf[0]!= 0 ){
    	   Errordeliver("when receiving information from socks4 proxy server","version of the reply code and should be 0,but server returns other code");
    	   return false;
      }
      switch(buf[1]){
         case 90:
          	// cout<<"finish communicating with proxy server "<<endl;
              return true;
         case 91:
        	    Errordeliver("socks4 proxy server not available","request rejected or failed");
        	    return false;
         case 92:
        	    Errordeliver("socks4 proxy server not available","request rejected becasue SOCKS server cannot connect to \
    	                   identd on the client");
        	    return false;
         case 93:
        	    Errordeliver("socks4 proxy server not available","request rejected because the client program and identd  \
    	                    report different user-ids");
        	    return false;
      }
}
/*    SOCKS 4A: A  Simple Extension to SOCKS 4 Protocol

            Ying-Da Lee
        yingda@best.com  or  yingda@esd.sgi.com

Please read SOCKS4.protocol first for an description of the version 4
protocol. This extension is intended to allow the use of SOCKS on hosts
which are not capable of resolving all domain names.

In version 4, the client sends the following packet to the SOCKS server
to request a CONNECT or a BIND operation:

        +----+----+----+----+----+----+----+----+----+----+....+----+
        ¦ VN ¦ CD ¦ DSTPORT ¦      DSTIP        ¦ USERID      ¦NULL¦
        +----+----+----+----+----+----+----+----+----+----+....+----+
# of bytes:      1    1      2              4          variable      1

VN is the SOCKS protocol version number and should be 4. CD is the
SOCKS command code and should be 1 for CONNECT or 2 for BIND. NULL
is a byte of all zero bits.

For version 4A, if the client cannot resolve the destination host's
domain name to find its IP address, it should set the first three bytes
of DSTIP to NULL and the last byte to a non-zero value. (This corresponds
to IP address 0.0.0.x, with x nonzero. As decreed by IANA  -- The
Internet Assigned Numbers Authority -- such an address is inadmissible
as a destination IP address and thus should never occur if the client
can resolve the domain name.) Following the NULL byte terminating
USERID, the client must sends the destination domain name and termiantes
it with another NULL byte. This is used for both CONNECT and BIND requests.

A server using protocol 4A must check the DSTIP in the request packet.
If it represent address 0.0.0.x with nonzero x, the server must read
in the domain name that the client sends in the packet. The server
should resolve the domain name and make connection to the destination
host if it can.

SOCKSified sockd may pass domain names that it cannot resolve to
the next-hop SOCKS server. 
*/
bool Lowlayer::Actsocks4aproxy(const int &sock,const sockaddr_in &in){
      unsigned char buf[BUFFERSIZE];
      int ret;
      int sendlen = Makesocks4arequest(buf,in);
      if(!Sendtoserver(sock,(const char*)buf,sendlen)){
    	     return false;
        }
      memset(buf,0,BUFFERSIZE);
      ret = Recvfromserver(sock,(char*)buf,BUFFERSIZE);
      if(ret==-1){
    	  return false;
      }
      if(ret != 8 ) {
    	  Errordeliver("socks4a proxy server not available","bad size of data received");
    	  return false;
     } 
     if( buf[0]!= 0 ){
    	  Errordeliver("socks4a proxy server not available","version of the reply code and should be 0,but server returns other code");
    	  return false;
     }
     switch(buf[1]){

         case 90:
        	 //cout<<"ready to use socks4a proxy server....... "<<endl;
              return true;
         case 91:
        	    Errordeliver("socks4a proxy server not available","request rejected or failed");
        	    return false;
         case 92:
        	    Errordeliver("socks4a proxy server not available","request rejected becasue SOCKS server cannot connect to \
    	                    identd on the client");
        	    return false;
         case 93:
          	 Errordeliver("socks4a proxy server not available","request rejected because the client program and identd  \
    	                   report different user-ids");
        	    return false;
    }
     return false;
}

bool Lowlayer::Prepareforsocks5proxy(const int &sock,const string &username,const string &password) {
      unsigned char buf[BUFFERSIZE];
      int sendlen;
      int ret;
      sendlen = Makesocks5methodrequest(buf);
      if(!Sendtoserver(sock,(const char*)buf,sendlen)){
    	     return false;
       }
      memset(buf,0,BUFFERSIZE);
      ret = Recvfromserver(sock,(char*)buf,BUFFERSIZE);
      if(ret==-1){
    	  return false;
      }
      if(ret != 2 ){
    	   Errordeliver("when receiving menthod communication result","bad size of data received");
    	   return false;
      }
      if(buf[0] != 0x05 ){
    	   Errordeliver("socks5 proxy server not available","proxy server returns the wrong version code ,it should be 0x05");
    	   return false;
      }
      if ( buf[1] ==0x00  ){
    	    //cout<<"finish communicating with socks5 proxy server about authentication....... "<<endl;
           return true;
      }
      else if(buf[1]==0x80){
    	  Errordeliver("socks5 proxy server not available","method select result:reserved for private methods");
    	  return false;
      }
      else if(buf[1]==0x03){
    	  Errordeliver("socks5 proxy server not available","method select result:IANA assigned");
    	  return false;
      }
      else if(buf[1]==0x01)
      {//GSSAPI
    	  Errordeliver("socks5 proxy server not available","method select result:GSSAPI");
    	  return false;
      }
      else if(buf[1]==0xFF)
      {
    	  Errordeliver("socks5 proxy server not available","method select result:no acceptable methods");
    	  return false;
      }
      else if(buf[1]!=0x02)
      {
    	  Errordeliver("socks5 proxy server not available","method select result:Unkow result");
    	  return false;
      }
      sendlen = Makesocks5authrequest(buf,username.c_str(),password.c_str());
      if(!Sendtoserver(sock,(const char*)buf,sendlen)){
    	   return false;
      }
      memset(buf,0,BUFFERSIZE);
      ret = Recvfromserver(sock,(char*)buf,BUFFERSIZE);
      if(ret==-1){
    	  return false;
      }
      if(ret != 2 ){
    	    Errordeliver("when receiving authentication result","bad size of data received");
    	    return false;
      }
      if(buf[0]!=0x01){
    	    Errordeliver("when receiving authentication result","proxy server returned the bad reply data,the first byte should be 0x01");
      }
      if (buf[1] == 0x00 ){
    	    //cout<<"finish communicating with socks5 proxy server about authentication....... "<<endl;
           return true;
      }
      else{
    	    Errordeliver("when receiving authentication result","get authentication failed");
    	    return false;
      }
}

bool Lowlayer::Actsocks5proxy(const int &sock,const sockaddr_in &in){
      unsigned char buf[BUFFERSIZE];
      int sendlen;
      int ret;
      memset(buf,0,BUFFERSIZE);
      sendlen = Makesocks5destrequest(buf,in);
      if(!Sendtoserver(sock,(const char*)buf,sendlen)){
    	   return false;
      }
      ret = Recvfromserver(sock,(char*)buf,BUFFERSIZE);
      if(ret==-1){
    	  return false;
      }
      if(ret <10 ){
    	   Errordeliver("when receiving destination communication result","bad size of data received");
    	   return false;
      }
      if(buf[ 0 ]!= 0x05 ){
    	  Errordeliver("when receiving destination communication result","proxy server returned bad version ");
    	  return false;
      }
      if(buf[ 2 ] != 0x00 ){
    	  Errordeliver("when receiving destination communication result","proxy server returned bad format of data ");
    	  return false;
      }
   // # X'00' success
   // # X'01' fail
   // # X'02' not allow
   // # X'03' net unreach
   // # X'04' host unreach
   // # X'05' connect refuse
   // # X'06' TTL timeout
   // # X'07' not support command
   // # X'08' not support address
   // # X'09' – X'FF' undef
      if(buf[1] == 0 ){
    	  //cout<<"ready to use socks5 proxy server....... "<<endl;
          return true;
      }
      else if(buf[1] == 0x01 ){
    	   Errordeliver("when receiving destination communication result","proxy server return :common socks error accrued");
    	   return false;
      }
      else if(buf[1] == 0x02 ){
    	   Errordeliver("when receiving destination communication result","proxy server return :connection not allowed");
    	   return false;
      }
      else if(buf[1] == 0x03 ){
    	   Errordeliver("when receiving destination communication result","proxy server return :net unreachable");
    	   return false;
      }
      else if(buf[1] == 0x04 ){
    	   Errordeliver("when receiving destination communication result","proxy server return :host unreachable");
    	   return false;
      }
      else if(buf[1] == 0x05 ){
    	  Errordeliver("when receiving destination communication result","proxy server return :connection refused");
    	  return false;
      }
      else if(buf[1] == 0x06 ){
    	   Errordeliver("when receiving destination communication result","proxy server return :TTL timeout");
    	   return false;
      }
      else if ( buf[ 1 ] == 0x07 ){
    	   Errordeliver("when receiving destination communication result","proxy server return :command not supported");
    	   return false;
      }
      else if ( buf[ 1 ] == 0x08 ){
    	  Errordeliver("when receiving destination communication result","proxy server return :address type not supported");
    	  return false;
      }
      else{
    	  Errordeliver("when receiving destination communication result","proxy server return :unkown error");
    	  return false;
      }
}
/// <------  public funtions

///////////////////////////////
/// ------>  protected funtions

int Lowlayer::Connecttoserver(const int &sock,const string &proxyserverip,const int &proxyport) {
      struct hostent *hp;
      //cout<<"socket :"<<sock<<" preparing to connect server:"<<proxyserverip<<" at port:"<<proxyport<<endl;
      hp = gethostbyname(proxyserverip.c_str());
      if (!hp){
    	  Errordeliver("error accrued while excuting function gethostbyname()","");
    	  return -1;
      }
      if(hp->h_addrtype != AF_INET && hp->h_addrtype != AF_INET6){ 
    	  Errordeliver("error accrued while connecting to proxy server","address type family can not be supported");
    	  return -1;
      }
      struct sockaddr_in servaddr;
      memset(&servaddr, 0, sizeof(servaddr));
      servaddr.sin_family = hp->h_addrtype;
      servaddr.sin_port = htons((short)proxyport);
      servaddr.sin_addr = *((struct in_addr*)(hp->h_addr));
      int ret;
      timeval tv;
      tv.tv_sec=utimeout;
      tv.tv_usec=0;
      if(setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(char *)&tv,sizeof(timeval))) {
           Errordeliver("error accrued while set 'receive' time out value for the socket",strerror(errno));
           /// error ocur while this operation might not be too serious ,so wo 
           ///  choose not to throw an error.
      }
      if(setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char *)&tv,sizeof(timeval))){
           Errordeliver("error accrued while set 'send' time out value for the socket",strerror(errno));
           /// error ocur while this operation might not be too serious ,so wo 
           ///  choose not to throw an error.
      }
      if((ret=(*oldconnect)(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))) < 0 ){
    	    Errordeliver("error accrued while connecting to proxy server ",strerror(errno)); 
      }else{
    	  //cout<<"socket :"<<sock<<" finish connecting to server:"<<proxyserverip<<" at port:"<<proxyport<<endl;
      }
      return ret;
}

bool Lowlayer::Sendtoserver(const int &sock,const char * buf, int buflen){
      int num=0;
      int remain=buflen;
      char *ptmp=(char *)buf;
      //cout<<"socket :"<<sock<<" preparing to send request to  proxy server "<<endl;
      while(remain>0){
          num = (*oldsend)(sock,ptmp+buflen-remain,remain, 0  );
          if(num<=0){
        	     Errordeliver("Error accrued while sending data to proxy server",strerror(errno));
        	     return false;
          }else{
               remain-=num;
            }
      }
      //cout<<"socket :"<<sock<<" finish sending request to  proxy server "<<endl;
      return true;
}

int Lowlayer::Recvfromserver(const int &sock,char *buf,int buflen){

      if( buflen <= 0 || buf == NULL ){
    	    Errordeliver("bad argument passed to Recvfromserver()",strerror(errno));
    	    return -1;
       }
      //cout<<"socket :"<<sock<<" preparing to receive replay from  proxy server "<<endl;
      int ret = (*oldrecv)(sock,buf,buflen, 0 );
      if(ret < 0 ){
    	    Errordeliver("network error while receiving data from proxy server",strerror(errno));
    	    return -1;
       }
      else if (ret == 0 ){
    	    Errordeliver("connection closed by proxy server while receiving data ",strerror(errno));
          return 0;
      }
      //cout<<"socket :"<<sock<<" finish receiving replay from  proxy server "<<endl;
      return ret;
}

bool Lowlayer::Formaddr_in(const string &host,const int &port,sockaddr_in &in){
      memset( &in,0,sizeof(sockaddr) );
      struct hostent *he;
      char *phost=(char*)host.c_str();
      if ((he=gethostbyname(phost)) == NULL){
    	    Errordeliver("Error accrued while using gethostbyname()",strerror(errno));
    	    return false;
      }
      in.sin_addr = *(( struct in_addr* )( he->h_addr ));
      in.sin_port = htons(( short )port);
      in.sin_family = he->h_addrtype;

      return true;
}

int  Lowlayer::Makesocks4request(unsigned char *buff,const sockaddr_in &in){
      unsigned short sport = in.sin_port;
      unsigned char * paddr = (unsigned char *)&in.sin_addr.s_addr;
      memset(buff,0,BUFFERSIZE);
      buff[0] = 0x04;
      buff[1] = 0x01;
      memcpy(buff + 2,&sport,2);
      memcpy(buff + 4,paddr,4);
      memcpy(buff + 8,"1",1);
      /// you can change "1" as any other you like
      buff[ 8 + 1 ] = 0;

      return 10;
}

int  Lowlayer::Makesocks4arequest(unsigned char *buff,const sockaddr_in &in){
      const char * paddr = inet_ntoa(in.sin_addr);
      memset(buff,0,BUFFERSIZE);
      buff[0] = 0x04;
      buff[1] = 0x01;
      short sport = in.sin_port;
      memcpy( buff + 2, &sport, 2 );
      buff[4] = buff[5] = buff[6] = 0;
      buff[7] = 0x01;
      memcpy(buff + 8, "1", 1 );

      buff[8 + 1] = 0;
      memcpy(buff + 8 + 1 + 1,paddr, strlen(paddr) );
      buff[8 + 1 + 1 + strlen(paddr)] = 0;

      return (11+strlen(paddr));
}

int  Lowlayer::Makesocks5methodrequest(unsigned char *buff){ 
      memset(buff,0,BUFFERSIZE);
      buff[0]=0x05;
      buff[1]=0x02;
      buff[2]=0x00;
      buff[3]=0x02;

      return 4;
}

int  Lowlayer::Makesocks5authrequest(unsigned char *buff,const char *username,const char *password){
      memset(buff,0,BUFFERSIZE);
      int ret = 0;
      buff[0] = 0x01;
      ret++;
      buff[ret] = strlen(username);
      ret++;
      memcpy(buff+ret,username,strlen(username));
      ret+= strlen(username);
      buff[ret] = strlen(password);
      ret++;
      memcpy(buff+ret,password,strlen(password));
      ret += strlen(password);

      return ret;
}

int  Lowlayer::Makesocks5destrequest(unsigned char *buff, const sockaddr_in &in){
      memset(buff,0,BUFFERSIZE);
      buff[0] = 0x05;
      buff[1] = 0x01; /////// use method connect
      buff[2] = 0x00; 
      if(in.sin_family==AF_INET)
           buff[3] = 0x01;
      const char* paddr = (const char*)&in.sin_addr.s_addr;
      memcpy(buff+4,paddr,4);
      int ret = 4 + 4;
      short sport = in.sin_port;
      memcpy(buff+ret,&sport,2);
      ret += 2;

      return ret;
}
int  Lowlayer::Makesocks5destrequest_udp(unsigned char *buff, const sockaddr_in &in){
      memset(buff,0,UDPTCPBUFFERSIZE);
      buff[0] = 0x05;
      buff[1] = 0x03; /////// use method udp
      buff[2] = 0x00; 
      buff[3] = 0x01;
      const char* paddr = (const char*)&in.sin_addr.s_addr;
      memcpy(buff+4,paddr,4);
      int ret = 4 + 4;
      short sport = in.sin_port;
      memcpy(buff+ret,&sport,2);
      ret += 2;
      return ret;
}

bool Lowlayer::Errordeliver(const string operation,const string errormsg){
      int fd;
      if((fd=open(FIFO_FILE,O_WRONLY|O_NONBLOCK))==-1){
          //perror("fopen");
          return false;
      }
      char *pname = getenv("PROGRAM_NAME");
      char *ptype = getenv("SHOWERRMODE");
      string totol;
      if(pname!=NULL){
           string name(pname);
           totol = name+string("@")+operation+string("@")+errormsg+string("@");
      }
      else{
           totol = string("Unknown program")+string("@")+operation+string("@")+errormsg+string("@");
      }
      if(ptype!=NULL){
    	  if(strcmp(ptype,"n")==0){
    		  
    	  }else if(strcmp(ptype,"Ui")==0){
    		  int writecount=-1;
    		  writecount=write(fd,totol.c_str(),totol.length());
    		  if(writecount<=0){
    			  perror("write()");
    		  }
    		  close(fd);
    	  }else{
    		  cout<<"-------------------------------------------"<<endl;
    		  cout<<"Error message:"<<operation<<endl;
    		  cout<<"Error detail"<<errormsg<<endl;
    		  cout<<"-------------------------------------------"<<endl;
    	  }
      }else{
    	  cout<<"-------------------------------------------"<<endl;
		  cout<<"Error message:"<<operation<<endl;
		  cout<<"Error detail"<<errormsg<<endl;
		  cout<<"-------------------------------------------"<<endl;
      }
      return true;
}
////////////////////////////////////////
/// <------  protected funtions
///////////////////////////////////////
/// ------>  private funtions
string Lowlayer::getipfromaddr_in(const struct sockaddr_in &in){
      return inet_ntoa(in.sin_addr);
}

int Lowlayer::getportfromaddr_in(const struct sockaddr_in &in){
      return ntohs(in.sin_port);
}

sa_family_t Lowlayer::getfamilyfromaddr_in(const struct sockaddr_in &in){
      return in.sin_family;
}

int Lowlayer::Base64Enc(char *dest,const  char*origtext,int size){
     const char base64_encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     int destlen = 0;

     while(size>0){
          *dest++ = base64_encoding[ (origtext[0] >> 2 ) & 0x3f];
          if(size>2){
              *dest++ = base64_encoding[((origtext[0] & 3) << 4) | (origtext[1] >> 4)];
              *dest++ = base64_encoding[((origtext[1] & 0xF) << 2) | (origtext[2] >> 6)];
              *dest++ = base64_encoding[origtext[2] & 0x3F];
          }
          else{
              switch(size){
                 case 1:
                        *dest++ = base64_encoding[(origtext[0] & 3) << 4 ];
                        *dest++ = '=';
                        *dest++ = '=';
                        break;
                 case 2:
                        *dest++ = base64_encoding[((origtext[0] & 3) << 4) | (origtext[1] >> 4)];
                        *dest++ = base64_encoding[((origtext[1] & 0x0F) << 2) | (origtext[2] >> 6)];
                        *dest++ = '=';
                        break;
              }
          }
          origtext +=3;
          size -=3;
          destlen +=4;
      }
     *dest = 0;
     return destlen;
}
/// <------  private funtions
///////////////////////////////////////
